<?php

declare(strict_types=1);

namespace app\service;

use app\model\CustomerGroupDescriptions;
use app\model\CustomerGroups;
use app\model\ProductLike;
use app\model\ProductViews;
use app\model\ShopFavorite;
use app\model\TravelCouponUser;
use app\model\User;
use app\model\UserAddresses;
use think\facade\Db;
use think\exception\ValidateException;
use app\model\Products;
use app\model\ScenicSpots;
use app\model\Tickets;

// 注释掉Firebase JWT，使用简单的JWT实现
// use Firebase\JWT\JWT;
// use Firebase\JWT\Key;

/**
 * 用户服务类
 * 提供用户认证、信息管理和全局用户上下文
 */
class UserService
{
    // 静态属性存储当前用户信息
    private static $currentUser = null;

    // JWT配置
    private $jwtConfig = [
        'secret_key' => 'travel_meow_jwt_secret_2024',
        'algorithm' => 'HS256',
        'expire_time' => 2592000, //一个月
        'refresh_expire_time' => 2592500 // 一个月
    ];
    private $userModel;

    public function __construct()
    {
        $this->userModel = new User();
        // 从配置文件读取JWT配置
        $jwtConfig = config('jwt', []);
        if (!empty($jwtConfig)) {
            $this->jwtConfig = array_merge($this->jwtConfig, $jwtConfig);
        }
    }

    /**
     * 用户登录验证
     */
    public function login(array $params): array
    {
        $miniProgramService = new MiniProgramService();
        $sessionRes = $miniProgramService->getSessionInfo($params['code']);
        if (empty($sessionRes)) {
            throw new \Exception('获取session失败');
        }
        $openid = $sessionRes['openid'];
        if (empty($openid)) {
            throw new \Exception('获取openid失败');
        }

        if ($params['login_type'] == 'login') {
            $user = $this->userModel->where('mini_open_id',  $openid)->find();
            if (empty($user)) {
                return [];
            }
            $user->save([
                'updated_at' => date('Y-m-d H:i:s'),
            ]);
        } else {
            // 解密手机号
            $phonEres = $miniProgramService->decryptData($sessionRes['session_key'], $params['phoneEncryptedData'], $params['phoneIv']);
            if (empty($phonEres)) {
                throw new \Exception('授权获取手机号失败，请重新授权');
            }
            // 把avatarUrl头像的base64编码解码并保存头像文件  string(5431) ""
            // 上传头像
            if (isset($params['avatarUrl']) && !empty($params['avatarUrl'])) {
                $params['avatarUrl'] = str_replace('data:image/jpeg;base64,', '', $params['avatarUrl']);
                $params['avatarUrl'] = base64_decode($params['avatarUrl']);
                // 目录是根目录的public/upload/avatar 
                // 判断目录是否存在
                if (!is_dir(root_path() . 'public/upload/avatar')) {
                    // 不存在则创建目录
                    mkdir(root_path() . 'public/upload/avatar', 0777, true);
                }

                $params['avatarUrl'] = file_put_contents(root_path() . 'public/upload/avatar/' . md5($openid) . '.jpg', $params['avatarUrl']);
                $params['avatarUrl'] = '/upload/avatar/avatar.jpg';
            } else {
                $params['avatarUrl'] = '';
            }
            // 根据openid检测用户是否存在
            $user = $this->userModel->where('mini_open_id',  $openid)->find();
            if (!$user) {
                // 不存在则创建新用户
                $user = $this->userModel->create([
                    'email' => $phonEres['phoneNumber'] . '@163.com',
                    'password' => md5('123456'),
                    'name' => $params['nickname'],
                    'avatar' => $params['avatarUrl'],
                    'status' => 'approved',
                    'customer_group_id' => CustomerGroups::where('level', 1)->value('id') ?? 1,
                    'locale' => 'zh_cn',
                    'active' => 1,
                    'code' => rand(100000, 999999),
                    'from' => 'mini',
                    'created_at' => date('Y-m-d H:i:s'),
                    'phone' => $phonEres['phoneNumber'],
                    'mini_open_id' => $openid,
                    'number' => generateUserNumber(),
                    'parent_id' => isset($params['share_user_id']) ? (int)$params['share_user_id'] : 0,
                ]);
            } else {
                // 存在则更新用户信息
                $user->save([
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);
            }
        }
        $user = $user->toArray();
        // 生成Token
        $token = $this->generateToken($user);
        return [
            'token' => $token,
            'userInfo' => $this->formatUserInfo($user)
        ];
    }

    /**
     * 生成简单Token
     */
    public function generateToken(array $user): string
    {
        $payload = [
            'user_id' => $user['id'],
            'username' => $user['name'],
            'role' => $user['role'] ?? 'user',
            'iat' => time(),
            'exp' => time() + $this->jwtConfig['expire_time']
        ];

        // 简单的Token实现
        $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
        $payloadJson = json_encode($payload);

        $base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
        $base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payloadJson));

        $signature = hash_hmac('sha256', $base64Header . '.' . $base64Payload, $this->jwtConfig['secret_key'], true);
        $base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

        return $base64Header . '.' . $base64Payload . '.' . $base64Signature;
    }

    /**
     * 验证简单Token
     */
    public function verifyToken(string $token): ?array
    {
        try {
            $parts = explode('.', $token);
            if (count($parts) !== 3) {
                return null;
            }

            list($base64Header, $base64Payload, $base64Signature) = $parts;

            // 验证签名
            $signature = base64_decode(str_replace(['-', '_'], ['+', '/'], $base64Signature));
            $expectedSignature = hash_hmac('sha256', $base64Header . '.' . $base64Payload, $this->jwtConfig['secret_key'], true);

            if (!hash_equals($signature, $expectedSignature)) {
                return null;
            }

            // 解析payload
            $payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $base64Payload)), true);
            // 检查Token是否过期
            if ($payload['exp'] < time()) {
                return null;
            }
            // 查询用户信息
            $user = User::where('id', $payload['user_id'])
                ->find();
            if (!$user || $user['active'] != 1 || $user['status'] != 'approved') {
                return null;
            }
            return $this->formatUserInfo($user->toArray());
        } catch (\Exception $e) {
            trace('Token验证失败: ' . $e->getMessage(), 'error');
            return null;
        }
    }

    /**
     * 获取用户信息
     */
    public function getUserInfo(int $userId): ?array
    {
        $user = Db::table('users')
            ->where('id', $userId)
            ->find();

        return $user ? $this->formatUserInfo($user) : null;
    }

    /**
     * 更新用户信息
     */
    public function updateUserInfo(int $userId, array $data): bool
    {
        // 过滤允许更新的字段
        $allowFields = ['nickname', 'avatar', 'phone'];
        $updateData = [];

        foreach ($allowFields as $field) {
            if (isset($data[$field])) {
                $updateData[$field] = $data[$field];
            }
        }

        if (empty($updateData)) {
            return true;
        }

        $updateData['updated_at'] = date('Y-m-d H:i:s');

        return Db::table('users')
            ->where('id', $userId)
            ->update($updateData) > 0;
    }

    /**
     * 格式化用户信息
     */
    private function formatUserInfo(array $user): array
    {
        $levelName = CustomerGroupDescriptions::where([
            'customer_group_id' => $user['customer_group_id'],
            'locale' => 'zh_cn'
        ])->value('name');
        $userAddress = UserAddresses::where('customer_id', $user['id'])->select()->toArray();
        return [
            'user_id' => (int)$user['id'],
            'username' => $user['name'],
            'avatar' => env('APP_URL') . $user['avatar'] ?? '',
            'email' => $user['email'] ?? '',
            'number' => $user['number'] ?? '',
            'phone' => $user['phone'] ?? '',
            'role' => $user['role'] ?? 'user',
            // 'status' => $user['status'] ?? 1,
            'active' => (int)$user['active'], //用户状态
            'active_desc' => (int)$user['active'] == 1 ? '正常' : '禁用',
            'status' => $user['status'], //审核状态
            'status_desc' => $user['status'] == 'approved' ? '通过' : '待审',
            'createTime' => $user['created_at'] ?? '',
            'open_id' => $user['mini_open_id'] ?? '',
            'balance' => (float)$user['balance'] ?? 0,
            'level' => $levelName ?? '游客',
            'address' => $userAddress,
            'address_id' => (int)$user['address_id'],
            'customer_group_id' => (int)$user['customer_group_id'],
            'voucher_balance' => (float)$user['voucher_balance'] ?? 0,
            'points' => (float)$user['points'] ?? 0,
            'commission_amount' => (float)$user['commission_amount'] ?? 0,
            'invite_code' => $user['invite_code'] ?? '',
            'agency_area' => $user['agency_area'] ?? '',
            'parent_id' => (int)$user['parent_id'] ?? 0,
            'role' => $user['user_role']
            // 'lastLogin' => $user['last_login'] ?? ''
        ];
    }

    /**
     * 设置当前用户信息（全局）
     */
    public static function setCurrentUser(?array $user): void
    {
        self::$currentUser = $user;
    }

    /**
     * 获取当前用户信息（全局）
     */
    public static function getCurrentUser(): ?array
    {
        return self::$currentUser;
    }

    /**
     * 获取当前用户ID
     */
    public static function getCurrentUserId(): ?int
    {
        return self::$currentUser['user_id'] ?? null;
    }

    /**
     * 获取当前用户名
     */
    public static function getCurrentUsername(): ?string
    {
        return self::$currentUser['username'] ?? null;
    }

    /**
     * 获取当前用户角色
     */
    public static function getCurrentUserRole(): ?string
    {
        return self::$currentUser['role'] ?? null;
    }
    // 获取余额
    public static function getCurrentUserBalance(): ?float
    {
        return self::$currentUser['balance'] ?? 0;
    }

    /**
     * 检查当前用户是否已登录
     */
    public static function isLoggedIn(): bool
    {
        return self::$currentUser !== null;
    }

    /**
     * 检查当前用户是否为管理员
     */
    public static function isAdmin(): bool
    {
        return self::getCurrentUserRole() === 'admin';
    }

    /**
     * 清除当前用户信息
     */
    public static function clearCurrentUser(): void
    {
        self::$currentUser = null;
    }

    /**
     * 检查用户权限
     */
    public static function hasPermission(string $permission): bool
    {
        if (!self::isLoggedIn()) {
            return false;
        }

        // 管理员拥有所有权限
        if (self::isAdmin()) {
            return true;
        }

        // 这里可以根据实际需求实现权限检查逻辑
        // 例如从数据库查询用户权限等

        return true; // 默认普通用户拥有基本权限
    }

    /**
     * 用户退出登录
     */
    public function logout(): void
    {
        self::clearCurrentUser();
    }

    /**
     * 刷新Token
     */
    public function refreshToken(string $token): ?string
    {
        $user = $this->verifyToken($token);
        if (!$user) {
            return null;
        }

        // 查询完整用户信息
        $fullUser = Db::table('users')
            ->where('id', $user['userId'])
            ->find();

        if (!$fullUser) {
            return null;
        }

        return $this->generateToken($fullUser);
    }

    /**
     * 修改密码
     */
    public function changePassword(int $userId, string $oldPassword, string $newPassword): bool
    {
        $user = Db::table('users')
            ->where('id', $userId)
            ->find();

        if (!$user) {
            throw new ValidateException('用户不存在');
        }

        // 验证旧密码
        if (!password_verify($oldPassword, $user['password'])) {
            throw new ValidateException('原密码错误');
        }

        // 更新密码
        $hashedPassword = password_hash($newPassword, PASSWORD_DEFAULT);

        return Db::table('users')
            ->where('id', $userId)
            ->update([
                'password' => $hashedPassword,
                'updated_at' => date('Y-m-d H:i:s')
            ]) > 0;
    }

    /**
     * 上传头像
     */
    public function uploadAvatar(int $userId, $file)
    {
        $filename = $userId . '.' . $file->getExtension();
        $file->move('uploads/avatar', $filename);
        return env('APP_URL') . '/uploads/avatar/' . $filename;
    }

    /**
     * 获取用户地址
     */
    public function getUserAddress(int $userId, $defaultAddressId = 0, $query = '')
    {
        $where = [];
        if (!empty($query)) {
            if ($query['id']) {
                $where[] = ['id', '=', $query['id']];
            }
        }
        $address = UserAddresses::where('customer_id', $userId)
            ->where($where)
            ->select()
            ->toArray();
        $formatData = [];
        foreach ($address as $item) {
            $tmpArr = [
                'id' => $item['id'],
                'name' => $item['name'],
                'phone' => $item['phone'],
                'site' => $item['zone'] . $item['city'] . $item['district'] . $item['address_1'],
                'tag' => []
            ];
            if ($item['id'] == $defaultAddressId) {
                $tmpArr['tag'][] = [
                    'tagText' => '默认'
                ];
            }
            $formatData[] = $tmpArr;
        }
        return $formatData;
    }

    /**
     * 保存用户地址
     */
    public function saveUserAddress(int $userId, $addressId, array $params)
    {
        // 验证参数

        try {
            $validate = validate([
                'consignee_name' => 'require',
                'consignee_phone' => 'require|max:11',
                'consignee_address' => 'require',
                'consignee_area' => 'require',
            ])->message([
                'consignee_name.require' => '请输入收货人姓名',
                'consignee_phone.require' => '请输入收货人手机号',
                'consignee_address.require' => '请输入收货人地址',
                'consignee_area.require' => '请选择区域',
            ]);
            if (!$validate->check($params)) {
                throw new \Exception($validate->getError());
            }
            if ($params['id'] > 0) {
                $id = (int)$params['id'];
                UserAddresses::where('id', (int)$id)->update([
                    'name' => $params['consignee_name'],
                    'phone' => $params['consignee_phone'],
                    'country_id' => 44,
                    'zone_id' => $params['consignee_area'][0]['area_id'],
                    'zone' => $params['consignee_area'][0]['area_name'],
                    'city_id' => $params['consignee_area'][1]['area_id'],
                    'city' => $params['consignee_area'][1]['area_name'],
                    'zipcode' => '000000',
                    'district_id' => $params['consignee_area'][2]['area_id'],
                    'district' => $params['consignee_area'][2]['area_name'],
                    'address_1' => $params['consignee_address'],
                    'address_2' => $params['consignee_address'],
                ]);
            } else {
                $id = UserAddresses::insertGetId([
                    'customer_id' => $userId,
                    'name' => $params['consignee_name'],
                    'phone' => $params['consignee_phone'],
                    'country_id' => 44,
                    'zone_id' => $params['consignee_area'][0]['area_id'],
                    'zone' => $params['consignee_area'][0]['area_name'],
                    'city_id' => $params['consignee_area'][1]['area_id'],
                    'city' => $params['consignee_area'][1]['area_name'],
                    'zipcode' => '000000',
                    'district_id' => $params['consignee_area'][2]['area_id'],
                    'district' => $params['consignee_area'][2]['area_name'],
                    'address_1' => $params['consignee_address'],
                    'address_2' => $params['consignee_address'],
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s'),
                ]);
            }

            if ($addressId <= 0 || $params['is_default'] == 1) {
                User::where('id', $userId)->update([
                    'address_id' => $id,
                ]);
            }
            return $id;
        } catch (\Exception $e) {
            throw new \Exception($e->getMessage());
        }
    }

    /**
     * 获取地址信息
     */
    public function getAddressInfo(int $id)
    {
        $address = UserAddresses::where('id', $id)->find();
        return $address;
    }

    /**
     * 获取用户详情
     */
    public function getUserDetail(int $userId)
    {
        $user = User::where('id', $userId)->find();
        if (!$user) {
            throw new \Exception('用户不存在');
        }
        $userDetail = $this->formatUserInfo($user->toArray());
        $userDetail['product_view_count'] = (new ProductViews())->getAllProductViewCount($userId);
        $userDetail['shop_favorite_count'] = (new ShopFavorite())->getAllShopFavoriteCount($userId);
        $userDetail['product_like_count'] = (new ProductLike())->getAllProductLikeCount($userId);
        // 获取待使用的优惠卷
        $userDetail['coupon_amount'] = (new TravelCouponUser())->getCouponAmount($userId);
        return $userDetail;
    }


    /**
     * 获取用户足迹
     */
    public function getMyFootprint($request)
    {
        $userId = $this->getCurrentUserId();
        $page = (int) $request->get('page', 1);
        $limit = (int) $request->get('limit', 10);
        $page = ($page - 1) * $limit;

        $query = ProductViews::where('customer_id', $userId);
        $productModel = new Products();
        $scenicSpotModel = new Tickets();
        $total = $query->count();
        $footprintList = $query->order('created_at', 'desc')->limit($page, $limit)->select();
        $formatData = [];
        // $productIds = array_column($footprintList,'product_id');
        // $productNames = $productModel->batchGetProductName($productIds);
        $productIds = [];
        $scenicSpotIds = [];
        foreach ($footprintList as $item) {
            $tmpItem = [
                'id' => $item->id,
                'product_id' => $item->product_id,
                'created_at' => date('Y-m-d', strtotime($item->created_at)),
                'title' => '',
                'prce' => 0,
                'view_type' => $item['view_type'],
            ];
            if ($item['view_type'] == 'goods') {
                $productIds[] = $item['product_id'];
                // $tmpItem['title'] = $productModel->getProductName($item['product_id']);
            } else if ($item['view_type'] == 'scenic_spot') {
                $scenicSpotIds[] = $item['product_id'];
            }
            $formatData[$item['product_id']] = $tmpItem;
        }

        $productNames = $productModel->batchGetProductInfo($productIds);
        $productNames = empty($productNames) ? [] : array_column($productNames, null, 'id');
        $scenicSpotNames = $scenicSpotModel->batchTicketInfo($scenicSpotIds);
        $scenicSpotNames = empty($scenicSpotNames) ? [] : array_column($scenicSpotNames, null, 'id');
        foreach ($formatData as $key => $item) {
            if ($item['view_type'] == 'goods') {
                $formatData[$key]['title'] = $productNames[$item['product_id']]['name'] ?? '';
                $formatData[$key]['price'] = $productNames[$item['product_id']]['price'] ?? 0;
                $formatData[$key]['image'] = $productNames[$item['product_id']]['image'] ?? '';
            } else if ($item['view_type'] == 'scenic_spot') {
                $formatData[$key]['title'] = $scenicSpotNames[$item['product_id']]['title'] ?? '';
                $formatData[$key]['price'] = $scenicSpotNames[$item['product_id']]['price'] ?? 0;
                $formatData[$key]['image'] = $scenicSpotNames[$item['product_id']]['cover_image'] ?? '';
            }
        }
        $formatData = array_values($formatData);
        return [
            'list' => $formatData,
            'total' => $total
        ];
        // $scenicSpotNames = $scenicSpotModel->batchGetScenicSpotName($scenicSpotIds);
    }

    /**
     * 获取用户收藏店铺
     */
    public function getMyCollectionShop($request)
    {
        $userId = $this->getCurrentUserId();
        $page = (int) $request->get('page', 1);
        $limit = (int) $request->get('limit', 10);
        $page = ($page - 1) * $limit;

        $query = ShopFavorite::alias('a1')
            ->leftJoin('sellers a2', 'a1.shop_id = a2.id')
            ->where('a1.user_id', $userId)
            ->field('a1.*,a2.store_name,a2.logo,a2.description,a2.seller_type,a2.status');
        $total = $query->count();
        $shopList = $query->order('created_at', 'desc')->limit($page, $limit)->select();
        //    active: '营业中',
        //         closed: '已打烊',
        //         busy: '繁忙'
        foreach ($shopList as $key => &$item) {
            // $shopList[$key]['logo'] = .$item['logo'] ?? '';
            $item['logo'] = env('IMAGE_URL') . $item['logo'];
            $item['status'] = $item['status'] == 1 ? 'active' : ($item['status'] == 2 ? 'closed' : 'busy');
            $item['rating'] = '5.00';
        }
        return [
            'list' => $shopList,
            'total' => $total
        ];
    }


    /**
     * 获取用户收藏商品
     */
    public function getMyCollectionGoods($request)
    {
        $userId = $this->getCurrentUserId();
        $page = (int) $request->get('page', 1);
        $limit = (int) $request->get('limit', 10);
        $page = ($page - 1) * $limit;
        $productModel = new Products();
        $query = ProductLike::where('user_id', $userId);
        $total = $query->count();
        if ($total == 0) {
            return [
                'list' => [],
                'total' => 0
            ];
        }
        $likeList = $query->order('created_at', 'desc')->limit($page, $limit)->select();
        $formatData = [];
        foreach ($likeList as $item) {
            $tmpItem = [
                'id' => $item->id,
                'product_id' => $item->product_id,
                'created_at' => date('Y-m-d', strtotime($item->created_at)),
                'title' => '',
                'prce' => 0,
                'view_type' => $item['view_type'],
            ];
            $formatData[$item['product_id']] = $tmpItem;
        }
        $productNames = $productModel->batchGetProductInfo(array_column($likeList->toArray(), 'product_id'));
        $productNames = empty($productNames) ? [] : array_column($productNames, null, 'id');
        foreach ($formatData as $key => $item) {
            $formatData[$key]['title'] = $productNames[$item['product_id']]['name'] ?? '';
            $formatData[$key]['price'] = $productNames[$item['product_id']]['price'] ?? 0;
            $formatData[$key]['image'] = $productNames[$item['product_id']]['image'] ?? '';
        }
        $formatData = array_values($formatData);
        return [
            'list' => $formatData,
            'total' => $total
        ];
    }
}
